home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 23 code / Multipane Dialogs Code / Utilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-18  |  26.3 KB  |  976 lines  |  [TEXT/MMCC]

  1. #include "Utilities.h"
  2.  
  3. short    gQDVersion;                /* major QD version #; 0 for original,
  4.                                             1 for color QD, 2 for 32-bit QD */
  5. short    gInitMPDUtils = 0;
  6. static Rect        gWindowPlacementRect;
  7. static short    gSystemVersion;            /* System version number */
  8. static short     gAppResRef;
  9.  
  10. /********************************************************************************
  11.  *
  12.  * Borrowed from DTS Lib
  13.  *
  14.  ********************************************************************************/
  15.  
  16. #define TopLeft(r)        (* (Point *) &(r).top)
  17. #define BotRight(r)        (* (Point *) &(r).bottom)
  18. enum { kQDOriginal = 0, kQD8Bit, kQD32Bit };    /* For use with gQDVersion */
  19. #define offsetof(structure,field) ((unsigned long)&((structure *) 0)->field)
  20.  
  21. typedef Boolean    (*TrackControlProcPtr)(ControlHandle ctl, short part, EventRecord *event);
  22. typedef void    (*ScrollProcPtr)(ControlHandle ctl, short part, short oldVal, short newVal);
  23. typedef void    (*DrawControlProcPtr)(ControlHandle ctl);
  24.  
  25. typedef struct ControlStyleInfo {
  26.     short                ctlID;
  27.     TrackControlProcPtr    trackProc;
  28.     ScrollProcPtr        scrollProc;
  29.     short                hArrowVal;
  30.     short                vArrowVal;
  31.     short                hPageVal;
  32.     short                vPageVal;
  33.     DrawControlProcPtr    drawControl;
  34.     short                fontSize;
  35.     Style                fontStyle;
  36.     Str32                font;
  37.     Str63                keyEquivs;
  38.     Str255                balloonHelp;
  39. } ControlStyleInfo;
  40. typedef ControlStyleInfo *ControlStyleInfoPtr;
  41.  
  42. static DrawControlProcPtr gDrawControl;
  43. static Handle            gScrollProc;
  44. static Handle             gPopupProc;
  45. static Handle            gButtonProcs[radioButProc + useWFont + 1];
  46. static ControlHandle    gWhichCtlHit;
  47. static long                gWhichCtlWhen;
  48. static Boolean            gWhichCtlDbl;
  49. static Boolean            gWhichCtlTracking;
  50.  
  51. Boolean GetCheckOrRadio(DialogPtr dlgPtr, short itemNo)
  52. {
  53.     short    iKind;
  54.     Handle    iHandle;
  55.     Rect    iRect;
  56.  
  57.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  58.     return(GetControlValue((ControlHandle)iHandle) != 0);
  59. }
  60.  
  61. void    ToggleCheck(DialogPtr dlgPtr, short chkItem)
  62. {
  63.     short    iKind;
  64.     Handle    iHandle;
  65.     Rect    iRect;
  66.  
  67.     GetDialogItem(dlgPtr, chkItem, &iKind, &iHandle, &iRect);
  68.     SetControlValue((ControlHandle) iHandle, !GetControlValue((ControlHandle)iHandle));
  69. }
  70.  
  71. void    SetCheckOrRadioButton(DialogPtr dlgPtr, short itemNo, short state)
  72. {
  73.     short    iKind;
  74.     Handle    iHandle;
  75.     Rect    iRect;
  76.  
  77.     GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect);
  78.     SetControlValue((ControlHandle)iHandle, state);
  79. }
  80.  
  81. char    LockHandleHigh(Handle theHandle)
  82. {
  83.     char    hstate;
  84.  
  85.     hstate = HGetState(theHandle);
  86.     MoveHHi(theHandle);
  87.     HLock(theHandle);
  88.     return(hstate);
  89. }
  90.  
  91. short    GetHexByte(char *cptr)
  92. {
  93.     short    val, i, chr;
  94.  
  95.     for (val = 0, i = 0; i < 2; ++i) {
  96.         chr = cptr[i];
  97.         if (chr == '=') return(cptr[++i]);
  98.         if (chr == '≈') {
  99.             chr = cptr[++i];
  100.             if ((chr >= 'a') && (chr <= 'z')) chr -= 32;
  101.             return(chr);
  102.         }
  103.         if (chr > 'F')
  104.             chr -= 0x20;
  105.         if (chr > '9')
  106.             chr -= ('A' - '9' - 1);
  107.         val = (val << 4) + chr - '0';
  108.     }
  109.     return(val);
  110. }
  111.  
  112. void    OutlineDialogItem(DialogPtr dlgPtr, short item)
  113. {
  114.     short    iKind;
  115.     Handle    iHandle;
  116.     Rect    iRect;
  117.  
  118.     GetDialogItem(dlgPtr, item, &iKind, &iHandle, &iRect);
  119.     OutlineControl((ControlHandle) iHandle);
  120. }
  121.  
  122. /* Given any control handle, this will draw an outline around it.  This is used
  123. ** for the default button of a window.  The extra nice feature here is that
  124. ** I’ll erase the outline for buttons that are inactive.  Seems like there
  125. ** should be a Toolbox call for getting a control’s hilite state.  Since there
  126. ** isn’t, I have to look into the control record myself.  This should be called
  127. ** for update and activate events.
  128. **
  129. ** The method for determining the oval diameters for the roundrect is a little
  130. ** different than that recommended by Inside Mac. IM I-407 suggests that you
  131. ** use a hardcoded (16,16) for the diameters.  However, this only looks good
  132. ** for small roundrects.  For larger ones, the outline doesn’t follow the inner
  133. ** roundrect because the CDEF for simple buttons doesn’t use (16,16).  Instead,
  134. ** it uses half the height of the button as the diameter.  By using this
  135. ** formula, too, our outlines look better. */
  136.  
  137. void    OutlineControl(ControlHandle button)
  138. {
  139.     WindowPtr    oldPort;
  140.     Rect        theRect;
  141.     PenState    curPen;
  142.     short        buttonOval;
  143.     RgnHandle    oldClip, newClip;
  144.     RGBColor    oldrgb;
  145.  
  146.     static RGBColor    whitergb = {0xFFFF, 0xFFFF, 0xFFFF};
  147.     static RGBColor    grayrgb  = {0x8000, 0x8000, 0x8000};
  148.     static RGBColor    blackrgb = {0x0000, 0x0000, 0x0000};
  149.  
  150.     if (button) {
  151.         if ((*button)->contrlVis) {
  152.             GetPort(&oldPort);
  153.             SetPort((*button)->contrlOwner);
  154.             GetPenState(&curPen);
  155.             PenNormal();
  156.             PenSize(kButtonFrameSize, kButtonFrameSize);
  157.  
  158.             theRect = (*button)->contrlRect;
  159.             InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset);
  160.             buttonOval = (theRect.bottom - theRect.top) / 2 + 2;
  161.  
  162.             GetClip(oldClip = NewRgn());
  163.             newClip = LocalScreenDepthRegion(4);
  164.             SectRgn(oldClip, newClip, newClip);
  165.             SetClip(newClip);
  166.  
  167.             if (!EmptyRgn(newClip)) {
  168.                 GetForeColor(&oldrgb);
  169.                 switch ((*button)->contrlHilite) {
  170.                     case kCntlActivate:
  171.                         RGBForeColor(&blackrgb);
  172.                         break;
  173.                     case kCntlDeactivate:
  174.                         RGBForeColor(&grayrgb);
  175.                         break;
  176.                     default:
  177.                         RGBForeColor(&whitergb);
  178.                         break;
  179.                 }
  180.                 FrameRoundRect(&theRect, buttonOval, buttonOval);
  181.                 RGBForeColor(&oldrgb);
  182.             }
  183.  
  184.             DiffRgn(oldClip, newClip, newClip);
  185.             SetClip(newClip);
  186.             if (!EmptyRgn(newClip)) {
  187.                 switch ((*button)->contrlHilite) {
  188.                     case kCntlActivate:
  189.                         PenPat((ConstPatternParam)&qd.black);
  190.                         break;
  191.                     case kCntlDeactivate:
  192.                         PenPat((ConstPatternParam)&qd.gray);
  193.                         break;
  194.                     default:
  195.                         PenPat((ConstPatternParam)&qd.white);
  196.                         break;
  197.                 }
  198.                 FrameRoundRect(&theRect, buttonOval, buttonOval);
  199.             }
  200.  
  201.             SetClip(oldClip);
  202.             DisposeRgn(oldClip);
  203.             DisposeRgn(newClip);
  204.  
  205.             SetPenState(&curPen);
  206.             SetPort(oldPort);
  207.         }
  208.     }
  209. }
  210.  
  211. /* Given a dialog ID and a window pointer the dialog relates to, this function
  212. ** will center the dialog’s rectangle before showing it on the proper screen.
  213. ** This follows the Apple Human Interface Guidelines for where to place a
  214. ** centered window on the screen.  If the dialog is not closely associated with
  215. ** another window, pass a nil for the window pointer of the related window.  If
  216. ** you pass a nil, the dialog is simply displayed where the resource
  217. ** would indicate. */
  218.  
  219. DialogPtr    GetCenteredDialog(short id, DialogPtr storage, WindowPtr relatedWindow, WindowPtr behind)
  220. {
  221.     DialogTHndl    dlogResource;
  222.     DialogPtr    dialog;
  223.     Boolean        oldVis;
  224.     char        hstate;
  225.     OSErr        err;
  226.     Rect        sizeInfo;
  227.  
  228.     dialog = nil;
  229.     if (!SimpleCanDialog()) {
  230.         dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err);
  231.         if (dlogResource) {
  232.             hstate = LockHandleHigh((Handle)dlogResource);
  233.             oldVis = (*dlogResource)->visible;
  234.             (*dlogResource)->visible = false;
  235.             dialog = GetNewDialog(id, storage, behind);
  236.             if (dialog) {
  237.                 SetRect(&sizeInfo, 0, 0, 0, 0);
  238.                 CenterWindow(dialog, relatedWindow, sizeInfo);
  239.                 if (oldVis)
  240.                     ShowWindow(dialog);
  241.             }
  242.             dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err);
  243.             if (dlogResource) {
  244.                 (*dlogResource)->visible = oldVis;
  245.                 HSetState((Handle)dlogResource, hstate);
  246.             }
  247.         }
  248.     }
  249.     return(dialog);
  250. }
  251.  
  252. /* Center a window within a particular device.  The device to center the window
  253. ** within is determined by passing a related window.  This allows related
  254. ** windows to be kept on the same device.  This is useful if an alert is related
  255. ** to a specific window, for example. */
  256.  
  257. Rect    CenterWindow(WindowPtr window, WindowPtr relatedWindow, Rect sizeInfo)
  258. {
  259.     WindowPtr    whichDevice;
  260.     Rect        deviceRect, oldWindowRect, newWindowRect, contentRect;
  261.     short        h, v, hh, vv;
  262.  
  263.     if (!(whichDevice = relatedWindow))
  264.         whichDevice = window;
  265.             /* If we have a window to center against, use the device for that window,
  266.             ** else use the device for the window that is getting centered. */
  267.  
  268.     deviceRect = GetWindowDeviceRectNMB(whichDevice);
  269.         /* We now have the rectangle of the device we want to center within. */
  270.  
  271.     if (!EmptyRect(&gWindowPlacementRect))
  272.         deviceRect = gWindowPlacementRect;
  273.  
  274.     contentRect = GetWindowContentRect(window);        /* Get where the window is now. */
  275.     h = hh = contentRect.right  - contentRect.left;
  276.     v = vv = contentRect.bottom - contentRect.top;
  277.     if (sizeInfo.left)
  278.         if (h < sizeInfo.left)
  279.             h = sizeInfo.left;
  280.     if (sizeInfo.right)
  281.         if (h > sizeInfo.right)
  282.             h = sizeInfo.right;
  283.     if (sizeInfo.top)
  284.         if (v < sizeInfo.top)
  285.             v = sizeInfo.top;
  286.     if (sizeInfo.bottom)
  287.         if (v > sizeInfo.bottom)
  288.             v = sizeInfo.bottom;
  289.     contentRect.right  = contentRect.left + h;
  290.     contentRect.bottom = contentRect.top  + v;
  291.  
  292.     oldWindowRect = GetWindowStructureRect(window);
  293.     oldWindowRect.right  += (h - hh);
  294.     oldWindowRect.bottom += (v - vv);
  295.     newWindowRect = oldWindowRect;
  296.  
  297.     PositionRectInRect(deviceRect, &newWindowRect, FixRatio(1, 2), FixRatio(1, 3));
  298.         /* Figure out the new window strucRect so we can compare it against
  299.         ** the old strucRect.  This will tell us how much to move the window. */
  300.  
  301.     OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left,
  302.                             newWindowRect.top  - oldWindowRect.top);
  303.         /* Calculate the new content rect. */
  304.  
  305.     MoveWindow(window, contentRect.left, contentRect.top, false);
  306.         /* Move the window to the new location. */
  307.  
  308.     return(contentRect);
  309. }
  310.  
  311. /* Given two rectangles, this function positions the second within the first
  312. ** one so that it maintains the spacing specified by the horzRatio and
  313. ** vertRatio parameters.  In other words, to center an inner rectangle
  314. ** hoizontally, but have its center be 1/3 from the top of the outer rectangle,
  315. ** call this function with horzRatio = FixRatio(1, 2), vertRatio =
  316. ** FixRatio(1, 3).  We use Fixed rather than floating point to avoid
  317. ** complications when mixing MC68881/non-MC68881 versions of Utilities. */
  318.  
  319. void    PositionRectInRect(Rect outerRect, Rect *innerRect, Fixed horzRatio, Fixed vertRatio)
  320. {
  321.     short    outerRectHeight;
  322.     short    outerRectWidth;
  323.     short    innerRectHeight;
  324.     short    innerRectWidth;
  325.     short    yLocation;
  326.     short    xLocation;
  327.  
  328.     outerRectHeight = outerRect.bottom - outerRect.top;
  329.     outerRectWidth = outerRect.right - outerRect.left;
  330.  
  331.     innerRectHeight = innerRect->bottom - innerRect->top;
  332.     innerRectWidth = innerRect->right - innerRect->left;
  333.         yLocation = Fix2Long(FixMul(Long2Fix(outerRectHeight - innerRectHeight), vertRatio))
  334.             + outerRect.top;
  335.         xLocation = Fix2Long(FixMul(Long2Fix(outerRectWidth - innerRectWidth), horzRatio))
  336.             + outerRect.left;
  337.  
  338.     innerRect->top = yLocation;
  339.     innerRect->left = xLocation;
  340.     innerRect->bottom = yLocation + innerRectHeight;
  341.     innerRect->right = xLocation + innerRectWidth;
  342. }
  343.  
  344. /* Given a window pointer, return the global rectangle that encloses the
  345. ** content area of the window. */
  346.  
  347. Rect    GetWindowContentRect(WindowPtr window)
  348. {
  349.     WindowPtr    oldPort;
  350.     Rect        contentRect;
  351.  
  352.     SetRect(&contentRect, 0, 0, 0, 0);
  353.     if (window) {
  354.         GetPort(&oldPort);
  355.         SetPort(window);
  356.         contentRect = window->portRect;
  357.         LocalToGlobalRect(&contentRect);
  358.         SetPort(oldPort);
  359.     }
  360.  
  361.     return(contentRect);
  362. }
  363.  
  364. /* This procedure is used to get the rectangle that surrounds the entire
  365. ** structure of a window.  This is true whether or not the window is visible.
  366. ** If the window is visible, then it is a simple matter of using the bounding
  367. ** rectangle of the structure region.  If the window is invisible, then the
  368. ** strucRgn is not correct.  To make it correct, then window has to be moved
  369. ** way off the screen and then made visible.  This generates a valid strucRgn,
  370. ** although it is valid for the position that is way off the screen.  It still
  371. ** needs to be offset back into the original position.  Once the bounding
  372. ** rectangle for the strucRgn is obtained, the window can then be hidden again
  373. ** and moved back to its correct location.  Note that ShowHide is used,
  374. ** instead of ShowWindow and HideWindow.  HideWindow can change the plane of
  375. ** the window.  Also, ShowHide does not affect the hiliting of windows.
  376. ** Note that using ShowHide to make the window visible has the unfortunate
  377. ** side-effect of changing the userState rect.  Since we make the window
  378. ** invisible prior to moving it back, userState gets left funky.  Due to this,
  379. ** we have to cache it prior to doing the ShowHide games. */
  380.  
  381. Rect    GetWindowStructureRect(WindowPtr window)
  382. {
  383. #define kOffscreenLoc 0x4000
  384.  
  385.     GrafPtr    oldPort;
  386.     Rect    structureRect, userState;
  387.     Point    windowLoc;
  388.  
  389.     SetRect(&structureRect, 0, 0, 0, 0);
  390.  
  391.     if (window) {
  392.  
  393.         if (((WindowPeek)window)->visible)
  394.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  395.  
  396.         else {
  397.             GetPort(&oldPort);
  398.             SetPort(window);
  399.             windowLoc  = GetGlobalTopLeft(window);
  400.             if (((WindowPeek)window)->spareFlag)
  401.                 userState = (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState;
  402.             MoveWindow(window, kOffscreenLoc, kOffscreenLoc, false);
  403.             ShowHide(window, true);
  404.             structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox;
  405.             ShowHide(window, false);
  406.             MoveWindow(window, windowLoc.h, windowLoc.v, false);
  407.             if (((WindowPeek)window)->spareFlag)
  408.                 (*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->userState = userState;
  409.             SetPort(oldPort);
  410.             OffsetRect(&structureRect, windowLoc.h - kOffscreenLoc, windowLoc.v - kOffscreenLoc);
  411.         }
  412.     }
  413.  
  414.     return(structureRect);
  415. }
  416.  
  417. /* Given a window, this will return the top left point of the window’s port in
  418. ** global coordinates.  Something this doesn’t include is the window’s drag
  419. ** region (or title bar).  This returns the top left point of the window’s
  420. ** content area only. */
  421.  
  422. Point    GetGlobalTopLeft(WindowPtr window)
  423. {
  424.     GrafPtr    oldPort;
  425.     Point    globalPt;
  426.  
  427.     GetPort(&oldPort);
  428.     SetPort(window);
  429.     globalPt = TopLeft(window->portRect);
  430.     LocalToGlobal(&globalPt);
  431.     SetPort(oldPort);
  432.     return(globalPt);
  433. }
  434.  
  435. void    LocalToGlobalRect(Rect *aRect)
  436. {
  437.     LocalToGlobal(&TopLeft(*aRect));
  438.     LocalToGlobal(&BotRight(*aRect));
  439. }
  440.  
  441. OSErr    SimpleCanDialog(void)
  442. {
  443.     OSErr                err;
  444.     ProcessSerialNumber    cpsn, fpsn;
  445.     Boolean                procsSame;
  446.  
  447.     err = noErr;
  448.     if (gSystemVersion >= 0x0700) {
  449.         err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
  450.             /* Ask the AppleEvent Manager if we can come forward */
  451.         GetCurrentProcess(&cpsn);        /* We may have been moved to the front. */
  452.         GetFrontProcess(&fpsn);
  453.         SameProcess(&cpsn, &fpsn, &procsSame);
  454.     }
  455.  
  456.     return(err);
  457. }
  458.  
  459. /* GetAppResource gets a resource from the application's resource file by
  460. ** resource ID. */
  461.  
  462. Handle    GetAppResource(ResType theType, short theID, OSErr *err)
  463. {
  464.     short    savedResFile;
  465.     Handle    returnHandle;
  466.  
  467.     savedResFile = CurResFile();
  468.     UseResFile(gAppResRef);
  469.     returnHandle = Get1Resource(theType, theID);
  470.     if (err) *err = ResError();
  471.     UseResFile(savedResFile);
  472.     return(returnHandle);
  473. }
  474.  
  475. RgnHandle    LocalScreenDepthRegion(short depth)
  476. {
  477.     RgnHandle    retRgn;
  478.     Point        pt;
  479.  
  480.     retRgn = ScreenDepthRegion(depth);
  481.  
  482.     pt.h = pt.v = 0;
  483.     GlobalToLocal(&pt);
  484.     OffsetRgn(retRgn, pt.h, pt.v);
  485.  
  486.     return(retRgn);
  487. }
  488.  
  489. RgnHandle    ScreenDepthRegion(short depth)
  490. {
  491.     RgnHandle        retRgn, tmpRgn;
  492.     GDHandle        device;
  493.     PixMapHandle    pmap;
  494.     Rect            rct;
  495.     GrafPtr            mainPort;
  496.  
  497.     retRgn = NewRgn();
  498.  
  499.     if (gQDVersion == kQDOriginal) {
  500.         if (depth == 1) {
  501.             GetWMgrPort(&mainPort);
  502.             rct = mainPort->portRect;
  503.             RectRgn(retRgn, &rct);
  504.         }
  505.     }
  506.     else {
  507.         tmpRgn = NewRgn();
  508.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  509.             if (
  510.                 (TestDeviceAttribute(device, screenDevice)) &&
  511.                 (TestDeviceAttribute(device, screenActive))
  512.             ) {
  513.                 pmap = (*device)->gdPMap;
  514.                 if ((*pmap)->pixelSize >= depth) {
  515.                     rct = (*device)->gdRect;
  516.                     RectRgn(tmpRgn, &rct);
  517.                     UnionRgn(retRgn, tmpRgn, retRgn);
  518.                 }
  519.             }
  520.         }
  521.         DisposeRgn(tmpRgn);
  522.     }
  523.  
  524.     return(retRgn);
  525. }
  526.  
  527. /* Given a window pointer, find the device that contains most of the window
  528. ** and return the device's bounding rectangle.  If this device is the main
  529. ** device, then remove the menubar area from the rectangle. */
  530.  
  531. Rect    GetWindowDeviceRectNMB(WindowPtr window)
  532. {
  533.     Rect    deviceRect, tempRect;
  534.  
  535.     SetRect(&deviceRect, 0, 0, 0, 0);
  536.  
  537.     if (window) {
  538.         deviceRect = GetWindowDeviceRect(window);
  539.         tempRect = GetMainScreenRect();
  540.         if (EqualRect(&deviceRect, &tempRect))
  541.             deviceRect.top += GetMBarHeight();
  542.     }
  543.  
  544.     return(deviceRect);
  545. }
  546.  
  547. Rect    GetMainScreenRect(void)
  548. {
  549.     GDHandle    mainDevice;
  550.     GrafPtr        mainPort;
  551.  
  552.     if (gQDVersion > kQDOriginal) {
  553.         mainDevice = GetMainDevice();
  554.         return((*mainDevice)->gdRect);
  555.     }
  556.     else {
  557.         GetWMgrPort(&mainPort);
  558.         return(mainPort->portRect);
  559.     }
  560. }
  561.  
  562. /* Given a window pointer, find the device that contains most of the window
  563. ** and return the device's bounding rectangle. */
  564.  
  565. Rect    GetWindowDeviceRect(WindowPtr window)
  566. {
  567.     if (gQDVersion > kQDOriginal) {
  568.         GDHandle WindowDeviceHandle = GetRectDevice(GetWindowStructureRect(window));
  569.         return((*WindowDeviceHandle)->gdRect);
  570.     } else {
  571.         return(GetMainScreenRect());
  572.     }
  573. }
  574.  
  575. /* Find the greatest overlap device for the given global rectangle. */
  576.  
  577. GDHandle    GetRectDevice(Rect globalRect)
  578. {
  579.     long        area, maxArea;
  580.     GDHandle    device, deviceToReturn;
  581.     Rect        intersection;
  582.  
  583.     deviceToReturn = GetMainDevice();            /* Use as default choice. */
  584.     maxArea = 0;
  585.  
  586.     for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  587.         if (TestDeviceAttribute(device, screenDevice)
  588.           && TestDeviceAttribute(device, screenActive)
  589.           && SectRect(&globalRect, &((*device)->gdRect), &intersection)) {
  590.             area = ((long)(intersection.right - intersection.left)) *
  591.                    ((long)(intersection.bottom - intersection.top));
  592.             if (area > maxArea) {
  593.                 deviceToReturn = device;
  594.                 maxArea = area;
  595.             }
  596.         }
  597.     }
  598.     return(deviceToReturn);
  599. }
  600.  
  601. void    DoDraw1Control(ControlHandle ctl, Boolean scrollBarsOnly)
  602. {
  603.     WindowPtr    window, oldPort;
  604.     Rect        rct, srct;
  605.     Point        org;
  606.     RgnHandle    oldClip, newClip;
  607.     Boolean        didPopup;
  608.  
  609.     window = (*ctl)->contrlOwner;
  610.     rct  = (*(window->visRgn))->rgnBBox;
  611.     srct = (*(window->clipRgn))->rgnBBox;
  612.     SectRect(&rct, &srct, &srct);
  613.  
  614.     rct = (*ctl)->contrlRect;
  615.     InsetRect(&rct, -4, -4);    /* Enclose possible control adornments. */
  616.     SectRect(&rct, &srct, &srct);
  617.     if (EmptyRect(&srct))
  618.         if (!(window->picSave))
  619.             return;
  620.  
  621.     if (IsScrollBar(ctl)) {
  622.         if (((WindowPeek)window)->hilited)
  623.             Draw1Control(ctl);
  624.         else {
  625.             if ((*ctl)->contrlVis) {
  626.                 GetPort(&oldPort);
  627.                 SetPort(window);
  628.                 rct = (*ctl)->contrlRect;
  629.                 FrameRect(&rct);
  630.                 InsetRect(&rct, 1, 1);
  631.                 EraseRect(&rct);
  632.                 SetPort(oldPort);
  633.             }
  634.         }
  635.     }
  636.     else {
  637.         if (!scrollBarsOnly) {
  638.             UseControlStyle(ctl);
  639.             didPopup = false;
  640.             if (gPopupProc) {        /* The popup control does not handle negative coords. */
  641.                 if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gPopupProc)) {
  642.                     didPopup = true;
  643.                     GetPort(&oldPort);
  644.                     SetPort(window);
  645.                     GetClip(oldClip = NewRgn());    /* We draw it once, so that internals   */
  646.                     SetRect(&srct, 0, 0, 0, 0);        /* are fixed up.  We don't want to show */
  647.                     ClipRect(&srct);                /* a flash though. */
  648.  
  649.                     RectRgn(newClip = NewRgn(), &(window->portRect));
  650.                     org.h = window->portRect.left;
  651.                     org.v = window->portRect.top;
  652.                     SetOrigin(0, 0);
  653.  
  654.                     OffsetRect(&((*ctl)->contrlRect), -org.h, -org.v);    /* Completely clipped out. */
  655.                     Draw1Control(ctl);                                    /* Just to fix internals.  */
  656.  
  657.                     SectRgn(newClip, oldClip, newClip);
  658.                     OffsetRgn(newClip, -org.h, -org.v);
  659.                     SetClip(newClip);
  660.                     Draw1Control(ctl);                /* Now really draw it. */
  661.  
  662.                     OffsetRect(&((*ctl)->contrlRect), org.h, org.v);
  663.                     SetOrigin(org.h, org.v);
  664.                     SetClip(oldClip);
  665.                     DisposeRgn(newClip);
  666.                     DisposeRgn(oldClip);
  667.  
  668.                     SetPort(oldPort);
  669.                 }
  670.             }
  671.             if (!didPopup) {
  672.                 if ((*ctl)->contrlVis) {
  673.                     if (gDrawControl)
  674.                         (*gDrawControl)(ctl);
  675.                     else
  676.                         Draw1Control(ctl);
  677.                 }
  678.             }
  679.             UseControlStyle(nil);
  680.             if (GetControlValue(ctl) == 1) {
  681.                 if (GetButtonVariant(ctl) == pushButProc)
  682.                     OutlineControl(ctl);
  683.             }
  684.         }
  685.     }
  686. }
  687.  
  688. void    ShowStyledControl(ControlHandle ctl)
  689. {
  690.     Boolean        didPopup;
  691.     WindowPtr    oldPort, window;
  692.     RgnHandle    oldClip, newClip;
  693.     Point        org;
  694.     Rect        srct;
  695.  
  696.     if (!(*ctl)->contrlVis) {
  697.  
  698.         didPopup = false;
  699.         if (gPopupProc) {        /* The popup control does not handle negative coords. */
  700.             if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gPopupProc)) {
  701.                 didPopup = true;
  702.                 GetPort(&oldPort);
  703.                 SetPort(window = (*ctl)->contrlOwner);
  704.                 GetClip(oldClip = NewRgn());    /* We draw it once, so that internals   */
  705.                 SetRect(&srct, 0, 0, 0, 0);        /* are fixed up.  We don't want to show */
  706.                 ClipRect(&srct);                /* a flash though. */
  707.  
  708.                 RectRgn(newClip = NewRgn(), &(window->portRect));
  709.                 org.h = window->portRect.left;
  710.                 org.v = window->portRect.top;
  711.                 SetOrigin(0, 0);
  712.  
  713.                 UseControlStyle(ctl);
  714.                 OffsetRect(&((*ctl)->contrlRect), -org.h, -org.v);    /* Completely clipped out. */
  715.                 ShowControl(ctl);                                    /* Just to fix internals.  */
  716.                 Draw1Control(ctl);
  717.  
  718.                 SectRgn(newClip, oldClip, newClip);
  719.                 OffsetRgn(newClip, -org.h, -org.v);
  720.                 SetClip(newClip);
  721.                 Draw1Control(ctl);                /* Now really show it. */
  722.                 UseControlStyle(nil);
  723.  
  724.                 OffsetRect(&((*ctl)->contrlRect), org.h, org.v);
  725.                 SetOrigin(org.h, org.v);
  726.                 SetClip(oldClip);
  727.                 DisposeRgn(newClip);
  728.                 DisposeRgn(oldClip);
  729.  
  730.                 SetPort(oldPort);
  731.             }
  732.         }
  733.  
  734.         if (!didPopup) {
  735.             (*ctl)->contrlVis = 255;
  736.             DoDraw1Control(ctl, false);
  737.         }
  738.     }
  739. }
  740.  
  741. void    UseControlStyle(ControlHandle ctl)
  742. {
  743.     WindowPtr            oldPort;
  744.     short                fnum;
  745.     ControlStyleInfo    cinfo;
  746.     static short        txFont, txSize;
  747.     static Style        txFace;
  748.     static WindowPtr    ctlWindow;
  749.  
  750.     if (!ctl) {
  751.         gDrawControl = nil;
  752.         if (ctlWindow) {
  753.             GetPort(&oldPort);
  754.             SetPort(ctlWindow);
  755.             TextFont(txFont);
  756.             TextSize(txSize);
  757.             TextFace(txFace);
  758.             SetPort(oldPort);
  759.         }
  760.         return;
  761.     }
  762.  
  763.     ctlWindow = nil;
  764.     if (GetControlStyle(ctl, &cinfo)) {
  765.         gDrawControl = cinfo.drawControl;
  766.         if (GetControlVariant(ctl) & useWFont) {
  767.             GetPort(&oldPort);
  768.             SetPort(ctlWindow = (*ctl)->contrlOwner);
  769.             txFont = ctlWindow->txFont;
  770.             txSize = ctlWindow->txSize;
  771.             txFace = ctlWindow->txFace;
  772.             TextFace(cinfo.fontStyle);
  773.             fnum = systemFont;
  774.             if (cinfo.font[0])
  775.                 GetFNum(cinfo.font, &fnum);
  776.             TextFont(fnum);
  777.             TextSize(cinfo.fontSize);
  778.             SetPort(oldPort);
  779.         }
  780.     }
  781. }
  782.  
  783. Boolean    GetControlStyle(ControlHandle ctl, void *cinfo)
  784. {
  785.     short    clen, tlen, ofst, ofst2, ofst3;
  786.     Ptr        ptr;
  787.  
  788.     clen = GetHandleSize((Handle)ctl);
  789.     tlen = (*ctl)->contrlTitle[0];
  790.     ofst = offsetof(ControlRecord,contrlTitle) + tlen + 1;
  791.     if (clen < ofst + sizeof(short)) return(false);
  792.  
  793.     if (cinfo) {
  794.         ptr = (Ptr)*ctl;
  795.         BlockMove(ptr + ofst, (Ptr)cinfo, clen - ofst);
  796.         ptr   = (Ptr)cinfo;
  797.         ofst  = offsetof(ControlStyleInfo,font);        /* font */
  798.         ofst2 = ofst  + ptr[ofst]  + 1;                    /* keyEquivs */
  799.         ofst3 = ofst2 + ptr[ofst2] + 1;                    /* balloonHelp */
  800.         BlockMove(ptr + ofst3, ptr + offsetof(ControlStyleInfo,balloonHelp), ptr[ofst3] + 1);
  801.         BlockMove(ptr + ofst2, ptr + offsetof(ControlStyleInfo,keyEquivs),   ptr[ofst2] + 1);
  802.     }
  803.  
  804.     return(true);
  805. }
  806.  
  807. Boolean    IsScrollBar(ControlHandle ctl)
  808. {
  809.     Rect            dummy;
  810.     ControlHandle    dummyCtl;
  811.  
  812.     if (!ctl) return(false);
  813.  
  814.     if (!gScrollProc) {
  815.         SetRect(&dummy, 0, 0, 16, 100);
  816.         dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  817.                               false, 1, 0, 1, scrollBarProc, 0L);
  818.         if (dummyCtl) {
  819.             gScrollProc = (*dummyCtl)->contrlDefProc;
  820.             DisposeControl(dummyCtl);
  821.         }
  822.     }
  823.  
  824.     return(StripAddress((*ctl)->contrlDefProc) == StripAddress(gScrollProc));
  825.         /* The handle may be locked, which means that the hi-bit
  826.         ** may be on, thus invalidating the compare.  Dereference the
  827.         ** handles to get rid of this possibility. */
  828. }
  829.  
  830. /* This function returns which kind of button the control is.  This does more
  831. ** than GetCVariant in that it makes sure that the control is actually a
  832. ** button.  It does this by comparing the defProc against the known defProc
  833. ** for the various button types.  For 7.0, there is only one defProc for all
  834. ** variants, but for pre-7.0, there is one defProc value for each variant.
  835. ** The method below handles either case. */
  836.  
  837. short    GetButtonVariant(ControlHandle ctl)
  838. {
  839.     short            i;
  840.     Rect            dummy;
  841.     ControlHandle    dummyCtl;
  842.  
  843.     if (ctl) {
  844.  
  845. /*
  846.         if (gGetButtonVariant) {
  847.             stop = false;
  848.             i = (*gGetButtonVariant)(ctl, &stop);
  849.             if (i >= 0) return(i);
  850.             if (stop)   return(-1);
  851.         }
  852. */
  853.  
  854.         for (i = pushButProc; i <= radioButProc + useWFont; ++i) {
  855.             if (i == radioButProc + 1)
  856.                 i = pushButProc + useWFont;
  857.             if (!gButtonProcs[i]) {
  858.                 SetRect(&dummy, 0, 0, 0, 0);
  859.                 dummyCtl = NewControl((*ctl)->contrlOwner, &dummy, (ConstStr255Param)"\p",
  860.                                       false, 1, 0, 1, i, 0L);
  861.                 if (dummyCtl) {
  862.                     gButtonProcs[i] = (*dummyCtl)->contrlDefProc;
  863.                     DisposeControl(dummyCtl);
  864.                 }
  865.             }
  866.             if (StripAddress((*ctl)->contrlDefProc) == StripAddress(gButtonProcs[i]))
  867.                 return(GetControlVariant(ctl) & (0xFFFF - useWFont));
  868.                     /* The handle may be locked, which means that the hi-bit
  869.                     ** may be on, thus invalidating the compare.  Dereference the
  870.                     ** handles to get rid of this possibility. */
  871.         }
  872.     }
  873.  
  874.     return(-1);
  875. }
  876.  
  877. Boolean    WhichControl(Point mouseLoc, long when, WindowPtr window, ControlHandle *ctlHit)
  878. {
  879.     Boolean                    found;
  880.     Rect                    rct;
  881.     ControlHandle            ctl, lastCtl;
  882.     static ControlHandle    lastWhenCtl;
  883.  
  884.     gWhichCtlTracking = false;
  885.  
  886.     found   = false;
  887.     lastCtl = nil;
  888.  
  889.     if (ctlHit)
  890.         *ctlHit = nil;
  891.  
  892.     if (window) {
  893.         ctl = ((WindowPeek)window)->controlList;
  894.         while (ctl) {
  895.             if ((*ctl)->contrlVis) {
  896.                 rct = (*ctl)->contrlRect;
  897.                 if (PtInRect(mouseLoc, &rct)) {
  898.                     found = true;            /* Return the last hit in the linked list, as */
  899.                     lastCtl = ctl;            /* it is drawn last, and therefore on top.    */
  900.                 }
  901.             }
  902.             ctl = (*ctl)->nextControl;
  903.         }
  904.     }
  905.  
  906.     if (ctlHit)
  907.         *ctlHit = lastCtl;
  908.  
  909.     gWhichCtlDbl = false;
  910.     if (when) {
  911.         gWhichCtlHit = lastWhenCtl;
  912.         lastWhenCtl  = lastCtl;
  913.         if (gWhichCtlHit == lastCtl)
  914.             if (when < gWhichCtlWhen + 30)
  915.                 gWhichCtlDbl = true;
  916.         gWhichCtlWhen = when;
  917.     }
  918.     gWhichCtlHit = lastCtl;
  919.  
  920.     return(found);
  921. }
  922.  
  923. /* Check to see if a given trap is implemented. */
  924.  
  925. short    NumToolboxTraps(void)
  926. {
  927.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  928.         return(0x200);
  929.     else
  930.         return(0x400);
  931. }
  932.  
  933. TrapType    GetTrapType(short theTrap)
  934. {
  935.     /* OS traps start with A0, Tool with A8 or AA. */
  936.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  937.         return(OSTrap);
  938.     else
  939.         return(ToolTrap);
  940. }
  941.  
  942. Boolean TrapExists(short theTrap)
  943. {
  944.     TrapType    theTrapType;
  945.  
  946.     theTrapType = GetTrapType(theTrap);
  947.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  948.         theTrap = _Unimplemented;
  949.  
  950.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  951. }
  952.  
  953. void    InitMPDUtils(void)
  954. {
  955.     long            gestaltResult;
  956.  
  957.     if (!gInitMPDUtils) {
  958.  
  959.         if (Gestalt(gestaltSystemVersion, &gestaltResult) == noErr)
  960.             gSystemVersion = gestaltResult;
  961.         else gSystemVersion = 0;
  962.  
  963.         /* We only concern ourselves with the major QD version number
  964.         ** 0 for original QD, 1 for 8-bit color QD, and 2 for 32-bit QD. */
  965.  
  966.         if (Gestalt(gestaltSystemVersion, &gestaltResult) == noErr)
  967.             gQDVersion = gestaltResult;
  968.         else gQDVersion = 0;
  969.         gQDVersion = (gQDVersion >> 8) & 0xFF;
  970.  
  971.         gAppResRef = CurResFile();            /* returns refNum of .rsrc file */
  972.  
  973.         gInitMPDUtils = true;
  974.     }
  975. }
  976.